﻿// 2025/10/21: 首个版本

using System;
using System.IO;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ASEva;
using ASEva.UIAvalonia;
using ASEva.Utility;
using ICSharpCode.SharpZipLib.Zip;
using System.Collections.Generic;
using Avalonia.Controls;

namespace CommonSource
{
    partial class GPUDecoderTestDialog : DialogPanel
    {
        public GPUDecoderTestDialog() // For designer
        {
            InitializeComponent();
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
        }

        public GPUDecoderTestDialog(GPUDecoderTestResults testResults, String iconResourceName = null)
        {
            InitializeComponent();
            SetResizableMode(300, 350, 300, 650);
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
            Icon = ResourceLoader.Load(iconResourceName)?.ToAvaloniaWindowIcon();
            Title = language["title"];

            model = new GPUDecoderTestDialogViewModel(this, testResults, language);
            DataContext = model;
        }

        public bool ResetRequested => model.ResetRequested;

        private LanguageSwitch language;
        private GPUDecoderTestDialogViewModel model;
    }

    partial class GPUDecoderTestDialogViewModel(Control view, GPUDecoderTestResults testResults, LanguageSwitch language) : ObservableObject
    {
        [ObservableProperty]
        private String mjpegDataState = testResults.TestDataAvailable["mjpeg"] ? language["data-generated"] : language["no-data"];

        [ObservableProperty]
        private String h264DataState = testResults.TestDataAvailable["h264"] ? language["data-generated"] : language["no-data"];

        [ObservableProperty]
        private String h265DataState = testResults.TestDataAvailable["h265"] ? language["data-generated"] : language["no-data"];

        [ObservableProperty]
        private bool manualInstallAvailable = !testResults.TestDataAvailable["mjpeg"] || !testResults.TestDataAvailable["h264"] || !testResults.TestDataAvailable["h265"];

        [RelayCommand]
        private async Task ManualInstall()
        {
            var filePath = await App.ShowOpenFileDialog(view, language["dialog-title"],
                filters: new Dictionary<string, string[]>
                {
                    [language["suffix"]] = [".zip"],
                });
            if (filePath != null && filePath.Length == 1) 
            {
                installPreEncodedPackage(filePath[0]);

                var newTestResults = await AgencyAsync.GetGPUDecoderTestResults();
                var mjpegDataOK = newTestResults.TestDataAvailable["mjpeg"];
                var h264DataOK = newTestResults.TestDataAvailable["h264"];
                var h265DataOK = newTestResults.TestDataAvailable["h265"];

                MjpegDataState = mjpegDataOK ? language["data-generated"] : language["no-data"];
                H264DataState = h264DataOK ? language["data-generated"] : language["no-data"];
                H265DataState = h265DataOK ? language["data-generated"] : language["no-data"];
                ManualInstallAvailable = !mjpegDataOK || !h264DataOK || !h265DataOK;
            }
        }

        private void installPreEncodedPackage(String zipFile)
        {
            if (AgencyLocal.ClientSide) return;

            var unZipDir = AgencyLocal.GetAppFilesRoot() + Path.DirectorySeparatorChar + "decoder_test" + Path.DirectorySeparatorChar;

            using (var s = new ZipInputStream(File.OpenRead(zipFile)))
            {
                ZipEntry theEntry = null;
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    var directoryName = Path.GetDirectoryName(theEntry.Name);
                    var fileName = Path.GetFileName(theEntry.Name);
                    if (!string.IsNullOrEmpty(directoryName))
                    {
                        Directory.CreateDirectory(unZipDir + directoryName);
                    }
                    if (directoryName != null && !directoryName.EndsWith("/"))
                    {
                    }
                    if (fileName != String.Empty)
                    {
                        using (var streamWriter = File.Create(unZipDir + theEntry.Name))
                        {
                            int size;
                            byte[] data = new byte[2048];
                            while (true)
                            {
                                size = s.Read(data, 0, data.Length);
                                if (size > 0) streamWriter.Write(data, 0, size);
                                else break;
                            }
                        }
                    }
                }
            }
        }

        private static String generateTestResult(Dictionary<String, ulong?> testResults, LanguageSwitch language)
        {
            var rows = new List<String>();
            foreach (var pair in testResults)
            {
                rows.Add(pair.Key + ": " + (pair.Value == null ? language["not-tested"] : (pair.Value.Value == 0 ? language["test-failed"] :
                    ((pair.Value.Value / (1024 * 1024)) + " Mpix/s"))));
            }
            return String.Join("\n", rows);
        }

        [ObservableProperty]
        private String testResult = generateTestResult(testResults.TestResults, language);

        [ObservableProperty]
        private bool canReset = true;

        [RelayCommand]
        private async Task Reset()
        {
            CanReset = false;

            await AgencyAsync.ResetGPUDecoderTestResults();
            ResetRequested = true;
            
            foreach (var key in testResults.TestResults.Keys)
            {
                testResults.TestResults[key] = null;
            }
            TestResult = generateTestResult(testResults.TestResults, language);
            await AgencyLocal.PopupNotice(language["reset-notice"]);
        }

        public bool ResetRequested { get; private set; } = false;
    }
}